package com.summerbird.mallchat.common.websocket;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.summerbird.mallchat.common.websocket.domain.enums.WSReqTypeEnum;
import com.summerbird.mallchat.common.websocket.domain.vo.request.WSBaseReq;
import com.summerbird.mallchat.common.websocket.service.WebSocketService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import static com.summerbird.mallchat.common.websocket.NettyUtil.TOKEN;

@Slf4j
@Sharable
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private WebSocketService webSocketService;

    /**
     * 用户第一次连接上ws时，需要将该channel进行管理
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        webSocketService = SpringUtil.getBean(WebSocketService.class);
        webSocketService.connect(ctx.channel());
    }

    /**
     * 断开ws后的操作
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        userOffLine(ctx.channel());
    }

    /**
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof WebSocketServerProtocolHandler.HandshakeComplete){
            System.out.println("握手成功");
            String token = NettyUtil.getAttr(ctx.channel(), TOKEN);
            // 如果用户第一次握手携带token，则直接认证
            if(StringUtils.isNotBlank(token)){
                webSocketService.authorize(ctx.channel(), token);
            }
        }
        if(evt instanceof IdleStateEvent){
            System.out.println("心跳事件");
            IdleStateEvent event = (IdleStateEvent)evt;
            if (event.state() == IdleState.READER_IDLE) {
                System.out.println("读空闲");
                // 用户下线
                userOffLine(ctx.channel());
            }
        }
    }

    /**
     * 用户下线主动管理
     * @param channel
     */
    private void userOffLine(Channel channel){
        webSocketService.remove(channel);
        // 断开连接
        channel.close();
    }

    /**
     * 处理客户端发送的消息
     * @param channelHandlerContext           the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
     *                      belongs to
     * @param textWebSocketFrame           the message to handle
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        String msg = textWebSocketFrame.text();
        WSBaseReq wsBaseReq = JSONUtil.toBean(msg, WSBaseReq.class);
        switch (WSReqTypeEnum.of(wsBaseReq.getType())) {
            case LOGIN:
                webSocketService.handleLoginReq(channelHandlerContext.channel());
                log.info("请求二维码 = " + textWebSocketFrame.text());
                break;
            case AUTHORIZE:
                webSocketService.authorize(channelHandlerContext.channel(), wsBaseReq.getData());
                break;
            case HEARTBEAT:
                break;
            default:
                log.info("未知类型");
        }
    }
}
